package com.example.demo.zookeeper;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.util.concurrent.CountDownLatch;

/**
 * @author liweizhi
 * @date 2020/6/21
 */
public class App {
    public static void main(String[] args) throws Exception {
        // 它会在这些server中做随机负载均衡
        String connectString = "192.168.200.11:2181,192.168.200.12:2181,192.168.200.13:2181,192.168.200.14:2181";
        // session超时时间,客户端挂了多久后,session会消失;
        // 设置太短的话,如果连接的那个server节点挂了,可能来不及fail over连接到其他节点,就会导致session过期,相当于客户端断开连接,则所有的临时节点
        int sessionTimeout = 60000;

        // 准备个门闩,因为下面是异步准备ZK对象的
        CountDownLatch countDownLatch = new CountDownLatch(1);

        /*
        watch 观察/监听事件
        watch只能注册于 读请求调用,get,exists等; 写操作是产生事件
        watch分为两类:
        1. new zk的时候传入的Watch,是session级别的,也是node的default watcher
        2. 对 path/node的watch,是一次性的

         */
        Watcher watcher = new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                Event.KeeperState state = event.getState();
                Event.EventType type = event.getType();
                String path = event.getPath();
                System.out.println("default watcher :" + event.toString());
                switch (state) {
                    case Disconnected:
                        break;
                    case SyncConnected:
                        countDownLatch.countDown();
                        break;
                    case AuthFailed:
                        break;
                    case ConnectedReadOnly:
                        break;
                    case SaslAuthenticated:
                        break;
                    case Expired:
                        break;
                    case Closed:
                        break;
                    default:
                        break;
                }
            }
        };
        // new ZooKeeper 异步准备zooKeeper对象
        ZooKeeper zooKeeper = new ZooKeeper(connectString, sessionTimeout, watcher);
        countDownLatch.await();
        ZooKeeper.States state = zooKeeper.getState();
        System.out.println(state);

        // create
        String path = zooKeeper.create("/hello", "world".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);

        // get 每个节点有存储的数据,还有节点的元数据,元数据通过这个stat返回
        Stat stat = new Stat();
        byte[] data = zooKeeper.getData(path, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println("data watcher :" + event);
                // node watcher是一次性的;但是这里可以继续get,传入this对象,即当前watcher;
                try {
                    zooKeeper.getData(path, this, stat);
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, stat);
        System.out.println(new String(data));
        // 这里get时使用的是注册Zookeeper时的那个watcher,即default watcher
//        System.out.println(new String(zooKeeper.getData(path, true, stat)));

        // update
        Stat statUpdate = zooKeeper.setData(path, "axiba".getBytes(), 0);
        Stat statUpdate2 = zooKeeper.setData(path, "axiba002".getBytes(), statUpdate.getVersion());


        // 这里阻塞一下,根据日志 可以知道连接到了哪个节点,把那个节点关掉, 观察日志发现,可以自动连接另一个节点 且session id没有变
        Thread.sleep(89757777);
    }
}
